package com.jinmdz.fmis.api.wrapper;

import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.constant.MessageConst;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.dao.dao.ChargeItemDao;
import com.jinmdz.fmis.dao.dao.ServiceItemDao;
import com.jinmdz.fmis.dao.model.charge.ChargeItem;
import com.jinmdz.fmis.dao.model.service.ServiceItem;
import com.jinmdz.fmis.mapper.entity.ChargeItemEntity;
import com.jinmdz.fmis.mapper.mapper.ChargeItemMapper;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

/**
 * 费用封装工具类
 *
 * @author LiCongLu
 * @date 2020-02-14 8:16
 */
@Component
public class ChargeWrapper extends BaseService {

    @Resource
    private ServiceItemDao serviceItemDao;

    @Resource
    private ChargeItemMapper chargeItemMapper;

    @Resource
    private ChargeItemDao chargeItemDao;

    /**
     * 插入业务费用
     *
     * @param userItem       当前帐号
     * @param businessCharge 业务费用
     * @param dictCode       字典编码
     * @param dataCode       字典编码值
     * @param purpose        用途值
     * @param ruleRemark     规则备注
     * @return
     * @author LiCongLu
     * @date 2020-02-14 8:18
     */
    public int insertBusinessCharge(UserItem userItem, ChargeItem businessCharge, String dictCode, Integer dataCode, String purpose, String ruleRemark) throws ActionException {
        // 获取业务费用项目
        ServiceItem serviceItem = serviceItemDao.getServiceItemByDictCode(dictCode, dataCode, purpose);
        if (serviceItem == null) {
            throw exception("不存在此业务费");
        }

        // 判断业务费用
        if (!DataUtil.equals(businessCharge.getServiceItemId(), serviceItem.getId())) {
            throw exception("提交业务费用主键与所选类型业务费主键不相同");
        }

        // 判断金额，当金额为空时，设置金额为0数量为1价格为0
        if (DataUtil.isNull(businessCharge.getItemCharge())) {
            businessCharge.setItemCharge(new BigDecimal(0));
        }

        if (DataUtil.isNull(businessCharge.getChargeTime())) {
            businessCharge.setChargeTime(nowDate());
        }

        // 判断销售状态
        if (DataUtil.valid(serviceItem.getDisableState())) {
            throw exception("此业务服务已禁止销售");
        }

        // 创建业务费用
        ChargeItemEntity chargeEntity = getEntity(userItem, ChargeItemEntity.class);
        BeanUtil.copy2Bean(businessCharge, chargeEntity);
        chargeEntity.setRemark(ruleRemark)
                .setAsSettled(0)
                .setChargeSettleId(null)
                .setAsBusiness(1)
                .setAsRefund(0)
                .setRefundId(null)
                .setAsUnsettled(businessCharge.getAsUnsettled());

        // 判断比较实收金额与优惠惠民的金额
        checkChargeForEntity(chargeEntity);

        // 插入业务费用
        chargeItemMapper.insertChargeItem(chargeEntity);
        // 判断业务费用结果
        if (DataUtil.invalid(chargeEntity.getId())) {
            throw exception("保存业务费用信息失败");
        }

        // 返回关联业务费用主键
        return chargeEntity.getId();
    }

    /**
     * 插入物品服务
     *
     * @param userItem      当前帐号
     * @param businessCode  业务编码
     * @param randomCode    随机码
     * @param businessType  业务类型编码
     * @param goodsServices 物品服务
     * @return
     * @author LiCongLu
     * @date 2020-02-14 10:17
     */
    public ArrayList<ChargeItemEntity> insertGoodsServices(UserItem userItem, String businessCode, String randomCode, String businessType, ArrayList<ChargeItem> goodsServices) throws ActionException {

        // 记录新增实体
        ArrayList<ChargeItemEntity> entityList = new ArrayList<>();

        // 物品服务为空时返回
        if (DataUtil.valid(goodsServices)) {
            // 获取物品服务
            ArrayList<ServiceItem> serviceItems = serviceItemDao.listServiceItemByBusinessType(businessType);
            HashMap<Integer, ServiceItem> serviceMap = new HashMap<>(16);
            for (ServiceItem serviceItem : serviceItems) {
                serviceMap.put(serviceItem.getId(), serviceItem);
            }

            // 获取当前时间
            Date nowDate = nowDate();

            // 记录已处理的物品服务id，避免重复提交
            ArrayList<Integer> serviceIds = new ArrayList<>();

            // 插入物品服务
            for (ChargeItem chargeItem : goodsServices) {
                // 所提交物品服务非当前业务所用
                if (!serviceMap.containsKey(chargeItem.getServiceItemId())) {
                    throw exception("存在不属于此业务的物品服务费用");
                }

                // 判断金额，当金额为空时，设置金额为0数量为1价格为0
                if (DataUtil.isNull(chargeItem.getItemCharge())) {
                    chargeItem.setItemCharge(new BigDecimal(0))
                            .setItemNumber(new BigDecimal(1))
                            .setItemPrice(new BigDecimal(0));
                }

                // 判断价格是否改变
                ServiceItem serviceItem = serviceMap.get(chargeItem.getServiceItemId());
                // 验证固定价格是否改动
                if (DataUtil.valid(serviceItem.getAsFixPrice())) {
                    if (chargeItem.getItemPrice().compareTo(serviceItem.getItemPrice()) != 0) {
                        throw exception("存在固定价格的物品服务被改变了价格");
                    }
                }

                // 判断销售状态
                if (DataUtil.valid(serviceItem.getDisableState())) {
                    throw exception("存在已禁止销售的物品服务");
                }

                // 判断费用日期
                if (DataUtil.isNull(chargeItem.getChargeTime())) {
                    chargeItem.setChargeTime(nowDate);
                }

                // 创建物品服务费用
                ChargeItemEntity chargeEntity = getEntity(userItem, ChargeItemEntity.class);
                BeanUtil.copy2Bean(chargeItem, chargeEntity);
                chargeEntity.setBusinessCode(businessCode)
                        .setRandomCode(randomCode)
                        .setItemUnit(serviceItem.getItemUnit())
                        .setAsSettled(0)
                        .setChargeSettleId(null)
                        .setAsUnsettled(0);

                // 判断比较实收金额与优惠惠民的金额
                checkChargeForEntity(chargeEntity);

                // 插入物品服务费用
                chargeItemMapper.insertChargeItem(chargeEntity);

                // 判断物品服务结果
                if (DataUtil.invalid(chargeEntity.getId())) {
                    throw exception("保存物品服务费用失败");
                }

                // 记录保存实体
                entityList.add(chargeEntity);

                // 记录已处理物品服务主键
                serviceIds.add(chargeEntity.getServiceItemId());
            }
        }
        return entityList;
    }

    /**
     * 判断比较实收金额与优惠惠民的金额
     *
     * @param chargeEntity 费用实体
     * @return
     * @author LiCongLu
     * @date 2020-03-04 13:33
     */
    public void checkChargeForEntity(ChargeItemEntity chargeEntity) throws ActionException {
        // 判断优惠金额
        if (DataUtil.isNull(chargeEntity.getDiscountCharge())) {
            chargeEntity.setDiscountCharge(new BigDecimal(0));
        }

        // 判断惠民金额
        if (DataUtil.isNull(chargeEntity.getBenefitCharge())) {
            chargeEntity.setBenefitCharge(new BigDecimal(0));
        }

        // 判断收费金额大小
        if (chargeEntity.getItemCharge().compareTo(new BigDecimal(0)) < 0) {
            throw exception("存在收费金额小于零的情况");
        }

        // 判断收费金额与优惠减免金额
        if (chargeEntity.getItemCharge().compareTo(chargeEntity.getDiscountCharge()
                .add(chargeEntity.getBenefitCharge())) < 0) {
            throw exception("存在优惠惠民大于收费金额的情况");
        }

        // 实际收费金额
        chargeEntity.setRealityCharge(chargeEntity.getItemCharge()
                .subtract(chargeEntity.getDiscountCharge())
                .subtract(chargeEntity.getBenefitCharge()));

        // 判断实际收费金额大小
        if (chargeEntity.getRealityCharge().compareTo(new BigDecimal(0)) < 0) {
            throw exception("存在实收金额小于零的情况");
        }
    }

    /**
     * 更新业务费用
     *
     * @param userItem       当前帐号
     * @param businessCharge 业务费用
     * @param dictCode       字典编码
     * @param dataCode       字典编码值
     * @param purpose        用途值
     * @param ruleRemark     规则备注
     * @return
     * @author LiCongLu
     * @date 2020-02-14 8:44
     */
    public void updateBusinessCharge(UserItem userItem, ChargeItem businessCharge, String dictCode, Integer dataCode, String purpose, String ruleRemark) throws ActionException {

        // 获取业务费用项目
        ServiceItem serviceItem = serviceItemDao.getServiceItemByDictCode(dictCode, dataCode, purpose);
        if (serviceItem == null) {
            throw exception("保存异常，不存在此业务费用");
        }

        // 判断金额，当金额为空时，设置金额为0数量为1价格为0
        if (DataUtil.isNull(businessCharge.getItemCharge())) {
            businessCharge.setItemCharge(new BigDecimal(0));
        }

        // 费用时间
        if (DataUtil.isNull(businessCharge.getChargeTime())) {
            businessCharge.setChargeTime(nowDate());
        }

        // 判断业务费用是否存在
        ChargeItemEntity chargeEntity = chargeItemMapper.getChargeItemById(businessCharge.getId());
        if (chargeEntity == null) {
            throw exception("请求业务费用主键错误，不存在此业务费用");
        }

        // 验证接运信息版本
        if (!DataUtil.equals(businessCharge.getVersion(), chargeEntity.getVersion())) {
            throw exception(versionError("业务费用"));
        }

        if (!DataUtil.equals(businessCharge.getServiceItemId(), serviceItem.getId())) {
            throw exception("提交业务费用主键与所选类型业务费主键不相同");
        }

        // 验证业务编码
        if (!businessCharge.getBusinessCode().equals(chargeEntity.getBusinessCode())) {
            throw exception("所提交业务编码与费用原有业务编码不相同");
        }

        // 判断是否结算，结算不再继续
        if (DataUtil.valid(chargeEntity.getAsSettled())) {
            return;
        }

        // 业务费用赋值
        BeanUtil.copy2Bean(businessCharge, chargeEntity);
        chargeEntity.setRemark(ruleRemark)
                .setAsSettled(0)
                .setChargeSettleId(null)
                .setAsBusiness(1)
                .setAsUnsettled(businessCharge.getAsUnsettled());

        // 判断比较实收金额与优惠惠民的金额
        checkChargeForEntity(chargeEntity);

        // 更新业务费用
        chargeItemMapper.updateChargeItem(chargeEntity);
    }

    /**
     * 更新物品服务
     *
     * @param userItem         当前帐号
     * @param businessCode     业务编码
     * @param randomCode       随机码
     * @param businessType     业务类型编码
     * @param businessChargeId 业务费用主键
     * @param goodsServices    物品服务
     * @return
     * @author LiCongLu
     * @date 2020-02-14 11:04
     */
    public ArrayList<ChargeItemEntity> updateGoodsServices(UserItem userItem, String businessCode, String randomCode
            , String businessType, Integer businessChargeId, ArrayList<ChargeItem> goodsServices) throws ActionException {

        // 记录处理实体
        ArrayList<ChargeItemEntity> entityList = new ArrayList<>();

        // 获取原物品服务
        ArrayList<ChargeItem> chargeOldItems = chargeItemDao.listChargeItemByRandomCode(businessCode, randomCode, businessChargeId);
        // 设置主键结构，以方便比较
        HashMap<Integer, ChargeItem> chargeOldMap = new HashMap<>(16);
        ArrayList<Integer> chargeOldIds = new ArrayList<>();
        ArrayList<Integer> serviceOldIds = new ArrayList<>();
        // 只记录非结算费用信息
        for (ChargeItem chargeItem : chargeOldItems) {
            if (DataUtil.invalid(chargeItem.getAsSettled())) {
                chargeOldMap.put(chargeItem.getId(), chargeItem);
                chargeOldIds.add(chargeItem.getId());
                serviceOldIds.add(chargeItem.getServiceItemId());
            }
        }

        // 当物品服务不为空时，更新操作
        if (DataUtil.valid(goodsServices)) {
            // 获取物品服务
            ArrayList<ServiceItem> serviceItems = serviceItemDao.listServiceItemByBusinessType(businessType);
            HashMap<Integer, ServiceItem> serviceMap = new HashMap<>(16);
            for (ServiceItem serviceItem : serviceItems) {
                serviceMap.put(serviceItem.getId(), serviceItem);
            }

            // 获取当前时间
            Date nowDate = nowDate();

            // 记录已处理的id，避免重复提交
            ArrayList<Integer> chargeIds = new ArrayList<>();
            // 记录已处理的物品服务id，避免重复提交
            ArrayList<Integer> serviceIds = new ArrayList<>();

            // 插入物品服务
            for (ChargeItem chargeItem : goodsServices) {
                // 所提交物品服务非当前业务所用
                if (!serviceMap.containsKey(chargeItem.getServiceItemId())) {
                    throw exception("存在不属于此业务的物品服务费用");
                }

                // 判断金额，当金额为空时，设置金额为0数量为1价格为0
                if (DataUtil.isNull(chargeItem.getItemCharge())) {
                    chargeItem.setItemCharge(new BigDecimal(0))
                            .setItemNumber(new BigDecimal(1))
                            .setItemPrice(new BigDecimal(0));
                }

                // 判断价格是否改变
                ServiceItem serviceItem = serviceMap.get(chargeItem.getServiceItemId());
                if (DataUtil.valid(serviceItem.getAsFixPrice())) {
                    if (chargeItem.getItemPrice().compareTo(serviceItem.getItemPrice()) != 0) {
                        throw exception("存在固定价格的物品服务被改变了价格");
                    }
                }

                // 判断费用日期
                if (chargeItem.getChargeTime() == null) {
                    chargeItem.setChargeTime(nowDate);
                }

                // 当主键为空时，按新增处理
                if (DataUtil.invalid(chargeItem.getId())) {

                    // 判断销售状态
                    if (DataUtil.valid(serviceItem.getDisableState())) {
                        throw exception("存在已禁止销售的物品服务");
                    }

                    // 创建物品服务费用
                    ChargeItemEntity chargeEntity = getEntity(userItem, ChargeItemEntity.class);
                    BeanUtil.copy2Bean(chargeItem, chargeEntity);
                    chargeEntity.setBusinessCode(businessCode)
                            .setRandomCode(randomCode)
                            .setItemUnit(serviceItem.getItemUnit())
                            .setAsSettled(0)
                            .setChargeSettleId(null)
                            .setAsBusiness(0)
                            .setAsUnsettled(0);

                    // 判断比较实收金额与优惠惠民的金额
                    checkChargeForEntity(chargeEntity);

                    // 插入物品服务费用
                    chargeItemMapper.insertChargeItem(chargeEntity);

                    // 记录已处理物品服务主键
                    serviceIds.add(chargeEntity.getServiceItemId());

                    // 判断物品服务结果
                    if (DataUtil.invalid(chargeEntity.getId())) {
                        throw exception("保存物品服务费用失败");
                    }

                    // 记录保存实体
                    entityList.add(chargeEntity);
                } else {
                    Integer chargeId = chargeItem.getId();

                    // 判断主键是否已处理过
                    if (chargeIds.contains(chargeId)) {
                        continue;
                    }

                    // 查询当前费用
                    ChargeItemEntity chargeEntity = chargeItemMapper.getChargeItemById(chargeId);
                    // 判断费用版本
                    if (!DataUtil.equals(chargeItem.getVersion(), chargeEntity.getVersion())) {
                        throw exception(versionError("物品服务"));
                    }

                    // 验证物品服务项目是否相同
                    if (!DataUtil.equals(chargeItem.getServiceItemId(), chargeEntity.getServiceItemId())) {
                        throw exception("提交物品服务与主键所指的原物品服务不相同");
                    }

                    // 验证业务编码
                    if (!businessCode.equals(chargeEntity.getBusinessCode())) {
                        throw exception("所提交业务编码与费用原有业务编码不相同");
                    }

                    // 再次判断是否结算
                    if (DataUtil.valid(chargeEntity.getAsSettled())) {
                        continue;
                    }

                    // 判断费用主键
                    if (!chargeOldMap.containsKey(chargeId)) {
                        throw exception("物品服务存在错误主键");
                    }

                    // 判断是否退费
                    if (DataUtil.valid(chargeEntity.getAsRefund())) {
                        throw exception("物品服务存在被退费或退费主键");
                    }

                    // 清除旧信息，剩余的将执行删除操作
                    chargeOldIds.remove(chargeId);
                    chargeOldMap.remove(chargeId);
                    // 记录id
                    chargeIds.add(chargeId);

                    // 物品服务赋值
                    BeanUtil.copy2Bean(chargeItem, chargeEntity);
                    chargeEntity.setBusinessCode(businessCode)
                            .setRandomCode(randomCode)
                            .setItemUnit(serviceItem.getItemUnit())
                            .setAsSettled(0)
                            .setChargeSettleId(null)
                            .setAsUnsettled(0);

                    // 判断比较实收金额与优惠惠民的金额
                    checkChargeForEntity(chargeEntity);

                    // 更新物品服务费用
                    chargeItemMapper.updateChargeItem(chargeEntity);

                    // 记录已处理物品服务主键
                    serviceIds.add(chargeEntity.getServiceItemId());

                    // 记录保存实体
                    entityList.add(chargeEntity);
                }
            }
        }
        return entityList;
    }

    /**
     * 删除物品服务
     *
     * @param userItem     当前帐号
     * @param businessCode 业务编码
     * @param randomCode   随机码
     * @param businessType 业务类型编码
     * @param deleteIds    物品服务主键
     * @return
     * @author LiCongLu
     * @date 2020-03-06 09:47
     */
    public ArrayList<ChargeItemEntity> deleteGoodsServices(UserItem userItem, String businessCode, String randomCode, String businessType, ArrayList<IdVersionData> deleteIds) throws ActionException {

        // 记录删除实体
        ArrayList<ChargeItemEntity> entityList = new ArrayList<>();

        // 当物品服务不为空时
        if (DataUtil.valid(deleteIds)) {
            // 获取物品服务
            ArrayList<ServiceItem> serviceItems = serviceItemDao.listServiceItemByBusinessType(businessType);
            HashMap<Integer, ServiceItem> serviceMap = new HashMap<>(16);
            for (ServiceItem serviceItem : serviceItems) {
                serviceMap.put(serviceItem.getId(), serviceItem);
            }

            // 物品
            ArrayList<IdVersionData> idList = deleteIds;
            // 记录费用主键
            ArrayList<Integer> chargeIds = new ArrayList<>();
            // 记录费用与版本号
            HashMap<Integer, Long> versionMap = new HashMap<>(16);
            for (IdVersionData item : idList) {
                if (!chargeIds.contains(item.getId())) {
                    chargeIds.add(item.getId());
                    versionMap.put(item.getId(), item.getVersion());
                }
            }

            // 去重
            chargeIds = DataUtil.repeatArrayList(chargeIds);

            // 验证Id是否重复
            if (idList.size() != chargeIds.size()) {
                throw exception("删除费用主键存在重复");
            }

            // 加载所要结算费用数据
            ArrayList<ChargeItem> chargeItems = chargeItemDao.listChargeItemByIds(businessCode, chargeIds);
            // 验证主键是否有效
            if (idList.size() != chargeItems.size()) {
                throw exception("费用明细已发生变化，请刷新后重新结算");
            }

            // 验证费用结算状态及费用数据版本
            for (ChargeItem chargeItem : chargeItems) {
                // 验证业务编码
                if (!businessCode.equals(chargeItem.getBusinessCode())) {
                    throw exception(MessageConst.BUSINESS_CODE_ERROR);
                }

                // 验证是否结算
                if (DataUtil.valid(chargeItem.getAsSettled())) {
                    throw exception("删除存在已经结算的费用");
                }

                // 验证是否退费
                if (DataUtil.valid(chargeItem.getAsRefund())
                        || DataUtil.valid(chargeItem.getRefundId())) {
                    throw exception("删除存在已经退费的费用");
                }

                // 验证批次
                if (!DataUtil.equals(chargeItem.getRandomCode(), randomCode)) {
                    throw exception("删除存在不同批次的费用");
                }

                // 所提交物品服务非当前业务所用
                if (!serviceMap.containsKey(chargeItem.getServiceItemId())) {
                    throw exception("存在不属于此业务的删除物品服务费用");
                }

                // 验证数据版本号
                Long version = versionMap.get(chargeItem.getId());
                // 判断费用版本
                if (!DataUtil.equals(chargeItem.getVersion(), version)) {
                    throw exception(versionError("删除费用"));
                }

                // 查询当前费用
                ChargeItemEntity chargeEntity = chargeItemMapper.getChargeItemById(chargeItem.getId());
                // 判断费用版本
                if (!DataUtil.equals(chargeItem.getVersion(), chargeEntity.getVersion())) {
                    throw exception(versionError("删除物品服务"));
                }

                // 再次判断是否结算
                if (DataUtil.valid(chargeEntity.getAsSettled())) {
                    throw exception("删除费用存在已结算");
                }

                // 删除物品费用
                chargeItemMapper.deletedForChargeItem(chargeEntity.getId(), userItem.getId(), chargeEntity.getVersion());

                // 记录保存实体
                entityList.add(chargeEntity);
            }
        }
        return entityList;
    }
}
